package testappserver;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ConcurrentLinkedQueue;

/** Позволяет серверу работать с каждым из клиентов единообразно
 */
public class SingleClient {
    //Сокет этого клиента
    private Socket mySocket;
    //Поток вывода. В него сервер выводит ответы на запросы клиентов
    private PrintWriter output;
    //Поток, в котором происходит работа с клиентом
    private Thread myThread;
    //Статус подключения
    private boolean isConnected;
    //Примитив синхронизации
    private Lock lock;

    private ConcurrentLinkedQueue<String> eventsQueue;

    //Конструктор (Получает ообъект-сокет)
    public SingleClient(Socket client) throws IOException {
        mySocket = client;
        output = new PrintWriter(client.getOutputStream(), true);
        myThread = GetProcThread();
        lock = new ReentrantLock();
        isConnected = false;
        eventsQueue = new ConcurrentLinkedQueue();
    }

    //Вызывает обработку этого клиента
    public void Connect() {
        lock.lock();
        try {
            isConnected = true;
            //запуск потока
            myThread.start();
        } finally {
            lock.unlock();
        }
    }

    //Останавливает обработку этого клиента
    public void Disconnect() throws IOException {
        lock.lock();
        try {
            //говорим, что клиент отключен
            isConnected = false;
        } finally {
            lock.unlock();
            output.println("close");
            //закрываем всё, что нужно закрыть
            output.close();
            mySocket.close();
        }
    }

    //Возвращает поток, в котором описана работа с данным клиентом
    private Thread GetProcThread() {
        return new Thread(new Runnable() {
            
            @Override
            public void run() {
                while (isConnected) {
                    if (eventsQueue.isEmpty()) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException ex) {
                        }
                    } else {
                        try {
                            output.println(eventsQueue.peek());
                        } catch (Exception e) {
                            
                        } finally {
                            eventsQueue.poll();
                        }
                    }
                }
            }
        });
    }

    public void AddCommand(String value) {
        eventsQueue.add(value);
    }
}
